﻿using System.Diagnostics.Contracts;
using System.Runtime.CompilerServices;
using System.Threading;
using O1.Kernel.Storage.Transactions;

namespace O1.Kernel.Storage
{
    internal partial class MultiVersionBinaryStorage
    {
        private readonly StorageSequence sequence;

        private long lastScavenged;

        private long lastCommittedTxId;

        public long LastCommittedTxId
        {
            get
            {
                return this.lastCommittedTxId;
            }
        }

        public void SetLastCommittedTx(long txId)
        {
            // Mutli-threaded, concurrent:
            var last = this.lastCommittedTxId;
            var tx = txId.SetCommitted();
            if (tx > last)
            {
                while (Interlocked.CompareExchange(ref this.lastCommittedTxId, tx, last) != last)
                {
                    last = this.lastCommittedTxId;
                    if (!(tx > last))
                    {
                        return;
                    }
                }
            }
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void BackgroundScavenge()
        {
            Contract.Ensures(this.lastScavenged > -2);

            var index = this.lastScavenged + 1;
            if (index >= this.Length)
            {
                this.lastScavenged = -1;
                return;
            }

            Contract.Assert(index > -1);
            if (this.storage.Collect(index))
            {
                this.sequence.Recycle(index);
            }

            this.lastScavenged = index;
        }
    }
}